from typing import Union

from helper.texter.Language import language_c
from helper.texter.Replacer import b0, b1, b2, b3
from helper.texter.TextBlock import get_bool_le_block, CodeBlock, get_line_block, get_assign_block, wrapped_block_mark


def get_c_block(
        template: str,
        *replace_list: Union[str, CodeBlock],
):
    return CodeBlock.get_block(language_c, template, *replace_list)


def get_c_empty_block(
        *replace_list: Union[str, CodeBlock],
):
    return get_c_block("", *replace_list)


def get_c_line_block(
        v: Union[str, CodeBlock] = "",
        line_end: str = ""
):
    cb = get_line_block(
        v,
        line_end,
    )
    cb.language = language_c
    return cb


def get_c_include_block(
        lib_name: str,
):
    return get_c_line_block(
        get_c_block(
            f"#include {b0}",
            lib_name,
        ),
    )


def get_c_arg_block(
        arg_type: str,
        arg_name: Union[str, CodeBlock],
):
    return get_c_block(
        f"{b0} {b1}",
        arg_type,
        arg_name,
    )


def get_c_arg_declare_block(
        arg_type: str,
        arg_name: Union[str, CodeBlock],
):
    return get_c_line_block(
        get_c_block(
            f"{b0} {b1};",
            arg_type,
            arg_name,
        ),
    )


def get_c_define_block(
        arg_k: str,
        arg_v: str,
):
    return get_c_line_block(
        get_c_block(
            f"#define {b0} {b1} ",
            arg_k,
            arg_v,
        ),
    )


def get_c_arg_add_add_block(
        arg: str,
):
    return get_c_block(
        f"{b0}++",
        arg,
    )


def get_c_return_block(
        arg: Union[str, CodeBlock],
):
    return get_c_line_block(
        get_c_block(
            f"return {b0};",
            arg,
        ),
    )


def get_c_fun_define_block(
        return_type: str,
        method_name: str,
        args_block: Union[str, CodeBlock],
        *replace_list: Union[str, CodeBlock],
):
    cb = get_c_block(
        f"\n{b0} {b1}({b2}) {{"
        f"{wrapped_block_mark}{b3}"
        f"\n}}",
        return_type,
        method_name,
        args_block,
        get_c_empty_block(*replace_list),
    )
    return cb


def get_c_main_fun_define_block(
        *replace_list: Union[str, CodeBlock],
):
    return get_c_fun_define_block(
        return_type="int",
        method_name="main",
        args_block=get_c_empty_block(),
        *replace_list,
    )


def get_c_for_block_1(
        block0: CodeBlock,
        block1: CodeBlock,
        block2: CodeBlock,
        *replace_list: Union[str, CodeBlock],
):
    cb = get_c_block(
        f"\nfor({b0}; {b1}; {b2}){{"
        f"{wrapped_block_mark}{b3}"
        f"\n}}",
        block0,
        block1,
        block2,
        get_c_empty_block(*replace_list),
    )
    return cb


def get_c_for_block_1_1(
        arg_i: str,
        i_min: Union[str, int],
        i_max: Union[str, int],
        *replace_list: Union[str, CodeBlock],
):
    return get_c_for_block_1(
        get_assign_block(arg_i, f"{i_min}"),
        get_bool_le_block(arg_i, f"{i_max}"),
        get_c_arg_add_add_block(arg_i),
        *replace_list,
    )
